﻿using movie.tool.library.hash;
using movie.tool.module.http;
using movie.tool.module.update.model;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;

namespace movie.tool.module.update.service
{
    public class UpdateManager
    {
        private static UpdateManager instance;
        public static UpdateManager Instance
        {
            get
            {
                if(instance == null)
                {
                    instance = new UpdateManager();
                }
                return instance;
            }
        }
        private UpdateManager()
        {

        }
        public async Task<Version> RemoteMovieToolVersion()
        {
            return await HttpInvoker.GetAsync<Version>("movieserver/appPackages/movie-tool/Windows/Lewin");
        }

        public async Task<Version> RemoteMovieToolUpdateVersion()
        {
            return await HttpInvoker.GetAsync<Version>("movieserver/appPackages/movie-tool-update/Windows/Lewin");
        }

        public string LocalVersion()
        {
            return GetAssemblyVersion(GetAssembly(), 3);
        }

        public async Task<bool> UpdateCheck()
        {
            Version v1 = await RemoteMovieToolVersion();
            if(v1 == null)
            {
                return false;
            }
            string v2 = LocalVersion();
            if (!Equals(v1.VersionName, v2))
            {
                MessageBoxResult result = MessageBox.Show("程序有更新,版本：" + v1.VersionName + ",是否更新", "程序更新", MessageBoxButton.OKCancel);
                if(result == MessageBoxResult.OK)
                {
                    return true;
                }
            }
            return false;
        }

        public async Task DownloadPackage()
        {
            Version version = await RemoteMovieToolVersion();
            await DownloadPackage(version);
            version = await RemoteMovieToolUpdateVersion();
            await DownloadPackage(version);
        }

        private async Task DownloadPackage(Version version)
        {
            if(version == null)
            {
                return;
            }
            List<AppPackageItem> items = await HttpInvoker.GetAsync<List<AppPackageItem>>("movieserver/appPackages/" + version.Id + "/files");
            if (items == null || items.Count == 0)
            {
                return;
            }
            foreach (AppPackageItem item in items)
            {
                string digest = await HttpInvoker.GetAsync<string>("movieserver/appPackageItems/" + item.Id + "/digest");
                await HttpInvoker.DownloadFile("movieserver/appPackageItems/" + item.Id + "/file", digest, item.RelativePath, AssembleRootPath(), UpdateTempPath());
            }
        }

        private string UpdateTempPath()
        {
            string path = AssembleRootPath();
            DirectoryInfo di = Directory.GetParent(path);
            path = di == null ? "" : di.FullName;
            if (string.IsNullOrWhiteSpace(path))
            {
                return string.Empty;
            }
            return Path.Combine(path, "update");
        }

        private string AssembleRootPath()
        {
            string path = GetAssembly().Location;
            DirectoryInfo di = Directory.GetParent(path);
            return di == null ? "" : di.FullName;
        }

        public void CopyMovieToolUpdateToTarget()
        {
            string path = UpdateTempPath();
            string target = AssembleRootPath();
            string[] files = Directory.GetFiles(path, "movie-tool-update*",SearchOption.AllDirectories);
            foreach (string item in files)
            {
                string relativePath = Path.GetRelativePath(path, item);
                string filePath = Path.Combine(target, relativePath);
                string sha1 = SHA1Hash.FileDigest(filePath);
                string sha2 = SHA1Hash.FileDigest(item);
                if (!object.Equals(sha1, sha2))
                {
                    File.Copy(item, filePath, true);
                }
            }
        }

        /// <summary>
        /// 执行更新程序,将
        /// </summary>
        public void RunUpdateProcess()
        {
            string file = Path.Combine(AssembleRootPath(), "movie-tool-update.exe");
            if (File.Exists(file))
            {
                ProcessStartInfo info = new ProcessStartInfo(file);
                Process process = new Process();
                process.StartInfo = info;
                process.Start();
                Process.GetCurrentProcess().CloseMainWindow();
            }
            else
            {
                throw new System.SystemException("更新程序不存在");
            }
        }

        /// <summary>
        /// 获取定义对象的程序集或者调用此函数的函数所在的程序集
        /// </summary>
        /// <param name="o">程序集中定义的对象</param>
        /// <returns>如果o不为null,则返回声明o的类型的程序集，如果o为范型，则返回定义o的程序集
        /// <para>如果o为null，则返回调用此函数的函数所在的程序集</para></returns>
        public static Assembly GetAssembly(object o)
        {
            if (o != null)
            {
                return o.GetType().Assembly;
            }
            return Assembly.GetCallingAssembly();
        }

        public static Assembly GetAssembly()
        {
            return GetAssembly(null);
        }

        /// <summary>
        /// 获取程序集版本信息
        /// </summary>
        /// <param name="assembly">程序集</param>
        /// <param name="fieldCount">版本的域宽</param>
        /// <returns>如果assembly为null则返回string.Empty，如果不为null，则返回指定域宽的版本信息</returns>
        public static string GetAssemblyVersion(Assembly assembly, int fieldCount)
        {
            if (assembly != null)
            {
                return assembly.GetName().Version.ToString(fieldCount);
            }
            return string.Empty;
        }
    }
}
